
/**
 * 1、通过对 formData 进行Proxy包装构建一棵监听列表
 * 2、在创建 field 实例时，注册监听列表
 * 3、将监听列表的监听事件挂载到监听树上
 *
 * 3、field 路径变更时，要变更监听对象
 * 4、field 实例销毁时，注销监听事件
 * 5、formata 属性变更时，同步调整监听树
 *
 * 问题：
 * 1、当 formdata 的数组属性添加一个元素时，如何保证明模糊监听能生效？
 * 2、同时监听多个字段时，如何避免重复调用
 * 3、proxy监听的对象类型是基于引用的，而对formData的监听是基于引用的。
 *
 * 衍生问题：
 * 3、如何合并值更新，同步提交（这个和监听无关）
 *
 * 优点：
 * 1、简化字段监听机制
 *    现在实现字段监听，涉及到FormDataManager, Path,Observer, Field ,链条太长
 *    通过Proxy的方式，只需要保留模模监听路径和含数组的相对监听路径的路径对象，
 * 2、实现精准通知
 *    现有机制是所有字段下发通知，字段内通过匹配规则判断是否需要触发Observer
 *    并且判断机制比较复杂，涉及到许多内部缓存，难以管理，容易出错
 * 3、可以把字段转换的功能结合进来处理，可以实时获取到转换后的FormData （有必要这么做吗？）
 *
 * 待优化点
 * 1、 form.getFieldVaule 要支持输出transform后的表单数据
 *
 * 实现方式
 * 先创建一个模型验证，不用直接接入SchemaForm
 * 创建多个测试用例，验证完整性
 * 验证通过后，再接入SchemaForm
 *
 * 
 * 想法
 * 怎么感觉都不需要Proxy了， onFieldChange本来就已经是触发点了
 * 只要把变更数据路径与监听路径匹配就可以实现精准通知
 * 无非变是集中式监听，还是分布式监听的问题
 * 
 * field实例创建时，通过register注册监听事件
 * 销毁时注销监听事件
 * 动态变更时，重新注册监听事件
 * 
 * 
 */

const baseStructor = {
  cb: new Set(),
  children: {}

}

function createPath(basePath = '', target, key) {
  switch (typeof target) {
    case 'object': return basePath
  }
}

function createDeepProxy(target) {

}

function deepProxy(obj, cb, parentPath = '') {
  if (typeof obj === 'object') {
    for (const key in obj) {
      if (typeof obj[key] === 'object') {
        obj[key] = deepProxy(obj[key], cb)
      }
    }
  }

  return new Proxy(obj, {
    /**
       * @param {Object, Array} target 设置值的对象
       * @param {String} key 属性
       * @param {any} value 值
       * @param {Object} receiver this
       */
    set: function (target, key, value, receiver) {
      if (typeof value === 'object') {
        value = deepProxy(value, cb)
      }

      const cbType = target[key] === undefined ? 'create' : 'modify'

      // 排除数组修改length回调
      if (!(Array.isArray(target) && key === 'length')) {
        cb(cbType, { target, key, value })
      }
      return Reflect.set(target, key, value, receiver)
    },
    deleteProperty(target, key) {
      cb('delete', { target, key })
      return Reflect.deleteProperty(target, key)
    }

  })
}

const data = {
  age: 10,
  array: [{ a: 1 }],
  data: {
    data: {
      data: {
        text: 1
      }
    }
  }
}
// 对象测试
const b = deepProxy(data, (type, data) => {
  console.log(type, data)
})

// b.array[1] = { a: [] }
// b.array[1].a[1] = 3
// delete b.data = {}
